﻿using System;
using System.Collections.ObjectModel;
using System.Xml.Linq;

namespace SilverMap
{
	#region MapItem
	/// <summary>
	/// Represents an item used to render tiles in the UIMap control.
	/// </summary>
	public class MapItem : IMapItem
	{
		/// <summary>
		/// Gets or sets the X position at which to place the item.
		/// </summary>
		public double X { get; set; }

		/// <summary>
		/// Gets or sets the Y position at which to place the item.
		/// </summary>
		public double Y { get; set; }

		/// <summary>
		/// Gets or sets the z-index of this item, determining the order in which it is drawn within the layer.
		/// </summary>
		public double Z { get; set; }

		/// <summary>
		/// Gets or sets the layer in which the item will be rendered.
		/// </summary>
		public int Layer { get; set; }

		/// <summary>
		/// Gets or sets the width of the item.
		/// </summary>
		public double Width { get; set; }

		/// <summary>
		/// Gets or sets the height of the item.
		/// </summary>
		public double Height { get; set; }

		/// <summary>
		/// Gets or sets the opacity of the item.
		/// </summary>
		public double Opacity { get; set; }

		/// <summary>
		/// Gets or sets the rotation of the item.
		/// </summary>
		public double Rotation { get; set; }

		/// <summary>
		/// Gets or sets the scale of the item.
		/// </summary>
		public double Scale { get; set; }

		/// <summary>
		/// Gets or sets the ITile instance representing the image for the current item.
		/// </summary>
		public ITile Tile { get; set; }
	}
	#endregion

	#region MapItemCollection
	/// <summary>
	/// Provides a collection of IMapItem instances.
	/// </summary>
	public class MapItemCollection : ObservableCollection<IMapItem>
	{
		/// <summary>
		/// Loads the current collection from the specified XElement.
		/// </summary>
		/// <param name="itemsElement">The XML element containing the items node.</param>
		/// <param name="getTileCallback">The method that will retrieve an ITile instance for the current item being created from XML.</param>
		/// <exception cref="System.ArgumentNullException"/>
		/// <exception cref="SilverMap.SilverMapException"/>
		public void Load(XElement itemsElement, GetTileCallback getTileCallback)
		{
			if (getTileCallback == null)
				throw new ArgumentNullException("getTileCallback");

			if (itemsElement == null)
				return;

			if (itemsElement.HasElements)
			{
				this.Clear();
				foreach (var itemElement in itemsElement.Elements())
				{
					var tile = getTileCallback(itemElement.GetInt32Value("tileId"));
					if (tile == null)
						throw new SilverMapException(SR.TileNotFound);

					this.Add(new MapItem
					{
						X = itemElement.GetDoubleValue("x"),
						Y = itemElement.GetDoubleValue("y"),
						Z = itemElement.GetDoubleValue("z"),
						Layer = itemElement.GetInt32Value("layer"),
						Width = itemElement.GetDoubleValue("width"),
						Height = itemElement.GetDoubleValue("height"),
						Opacity = itemElement.GetDoubleValue("opacity"),
						Rotation = itemElement.GetDoubleValue("rotation"),
						Scale = itemElement.GetDoubleValue("scale"),
						Tile = tile
					});
				}
			}
		}

		/// <summary>
		/// Saves the current collection as nodes of the specified XElement.
		/// </summary>
		/// <param name="itemsElement">The XML node in which to add the individual item nodes.</param>
		/// <exception cref="System.ArgumentNullException"/>
		public void Save(XElement itemsElement)
		{
			foreach (var item in this)
			{
				var itemElement = new XElement("item");
				itemsElement.Add(itemElement);

				itemElement.Add(new XAttribute("x", item.X));
				itemElement.Add(new XAttribute("y", item.Y));
				itemElement.Add(new XAttribute("z", item.Z));
				itemElement.Add(new XAttribute("layer", item.Layer));
				itemElement.Add(new XAttribute("width", item.Width));
				itemElement.Add(new XAttribute("height", item.Height));
				itemElement.Add(new XAttribute("opacity", item.Opacity));
				itemElement.Add(new XAttribute("rotation", item.Rotation));
				itemElement.Add(new XAttribute("scale", item.Scale));
				itemElement.Add(new XAttribute("tileId", item.Tile.ID));
			}
		}
	}
	#endregion
}
